package com.heima.comment.service.impl;

import com.alibaba.fastjson.JSON;
import com.heima.apis.article.IArticleClient;
import com.heima.apis.user.IUserClient;
import com.heima.comment.pojos.ApComment;
import com.heima.comment.pojos.ApCommentLike;
import com.heima.comment.pojos.CommentVo;
import com.heima.comment.service.CommentService;
import com.heima.common.constants.HotArticleConstants;
import com.heima.model.article.pojos.ApArticle;
import com.heima.model.article.pojos.ApArticleConfig;
import com.heima.model.comment.dtos.CommentDto;
import com.heima.model.comment.dtos.CommentLikeDto;
import com.heima.model.comment.dtos.CommentSaveDto;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.mess.UpdateArticleMess;
import com.heima.model.user.pojos.ApUser;
import com.heima.model.wemedia.pojos.WmChannel;
import com.heima.utils.thread.AppThreadLocalUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class CommentServiceImpl implements CommentService {

    @Autowired
    private IUserClient userClient;

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private IArticleClient articleClient;

    @Autowired
    private KafkaTemplate<String, String> kafkaTemplate;

    /**
     * 保存评论
     * @param dto
     * @return
     */
    @Override
    public ResponseResult saveComment(CommentSaveDto dto) {
        //1.检查参数
        if (dto == null || StringUtils.isBlank(dto.getContent()) || dto.getArticleId() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }

        //校验文章是否可以评论
        if (!checkParam(dto.getArticleId())) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID, "该文章评论权限已关闭");
        }

        if (dto.getContent().length() > 150) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID, "评论内容不能超过150字");
        }

        //2.判断当前app用户是否登录
        ApUser user = AppThreadLocalUtil.getUser();
        if (user == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        }


        //3.TODO 安全检查

        //4.保存评论
        //ApUser dbUser = userClient.findUserById(user.getId());
        ResponseResult responseResult = userClient.findUserById(user.getId());
        log.info("远程接口查询到的app端用户信息返回结果：{}",responseResult.getData());
        ApUser dbUser = null;
        log.info("responseResult.getCode()是：{}",responseResult.getCode());
        if(responseResult.getCode().equals(200)){//远程接口调用成功
            log.info("远程接口调用成功");
            //获得app端用户信息(json数据)
            String dbUserJson = JSON.toJSONString(responseResult.getData());
            //转换成对象
            dbUser = JSON.parseObject(dbUserJson, ApUser.class);
            //通过用户ID查找当前登录用户的信息。如果用户不存在，则返回错误信息。
            if (dbUser == null) {
                log.info("当前登录信息有误");
                return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID,
                        "当前登录信息有误");
            }

        }

        //创建一个新的评论对象 apComment。
        ApComment apComment = new ApComment();
        //评论者的ID。
        apComment.setAuthorId(user.getId());
        //评论内容。
        apComment.setContent(dto.getContent());
        //评论创建时间（当前时间）。
        apComment.setCreatedTime(new Date());
        //评论关联的文章ID。
        apComment.setEntryId(dto.getArticleId());
        //评论者的头像。
        apComment.setImage(dbUser.getImage());
        //评论者的名称。
        apComment.setAuthorName(dbUser.getName());
        //评论的点赞数（初始化为0）。
        apComment.setLikes(0);
        //评论的回复数（初始化为0）。
        apComment.setReply(0);
        // 评论类型（初始化为0，可能表示普通评论）。
        apComment.setType((short) 0);
        // 文章标记
        // 0 普通评论  1 热点评论
        // 2 推荐评论  3 置顶评论
        // 4 精品评论  5 大V 评论
        apComment.setFlag((short) 0);
        //将评论数据保存到MongoDB数据库中
        mongoTemplate.save(apComment);

        //发送消息，进行聚合
        //消息发送封装类UpdateArticleMess(点赞/取消点赞/浏览文章之后，
        // 需要记录次数，然后。。。。保存到redis中)
        UpdateArticleMess mess = new UpdateArticleMess();
        //设置文章ID
        mess.setArticleId(dto.getArticleId());
        //增加的评论数（这里是1）
        mess.setAdd(1);
        //设置消息类型(评论)
        mess.setType(UpdateArticleMess.UpdateArticleType.COMMENT);
        //将消息转换为JSON格式，并通过 kafkaTemplate
        //发送到指定的Kafka主题 HOT_ARTICLE_SCORE_TOPIC，
        //以便进行后续处理（如更新热度评分等）
        // 发送更新文章的评论数的消息(实时更新文章的评论数) stream数据聚合((article服务需要先注入kafka)
        kafkaTemplate.send(HotArticleConstants.HOT_ARTICLE_SCORE_TOPIC,
                JSON.toJSONString(mess));
        //发消息给kafka，kafka再发消息给stream(文章微服务article.stream.HotArticleStreamHandler)，让它聚合数据，
        // 然后更新聚合后的数据到redis与mysql(直接去到文章微服务ApArticleServiceImpl里的updateArticle)


        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    /**
     * 校验文章是否可以评论
     * @param articleId
     * @return
     */
    private boolean checkParam(Long articleId) {
        //是否可以评论
        ResponseResult configResult = articleClient.findArticleConfigByArticleId(articleId);
        //得到ResponseResult.okResult(ApArticleConfig)

        if (!configResult.getCode().equals(200) || configResult.getData() == null) {
            return false;
        }

        ApArticleConfig apArticleConfig
                = JSON.parseObject(JSON.toJSONString(configResult.getData()), ApArticleConfig.class);
        //true: 可以评论 1 false: 不可评论 0
        if (apArticleConfig == null || !apArticleConfig.getIsComment()) {
            return false;
        }

        return true;
    }


    /**
     * 保存评论的点赞信息(点赞数 + 1 |记录是谁点的赞)
     * @param dto (评论id + 0.点赞1：取消点赞)
     * @return
     */
    @Override
    public ResponseResult like(CommentLikeDto dto) {
        //1.检查参数
        if (dto == null || dto.getCommentId() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }

        //2.判断是否登录
        ApUser user = AppThreadLocalUtil.getUser();
        if (user == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        }

        ApComment apComment = mongoTemplate.findById(dto.getCommentId(), ApComment.class);

        //3.点赞  0：点赞  1：取消点赞
        //检查apCommentRepay是否存在且操作类型是否为点赞（dto.getOperation() == 0）
        if (apComment != null && dto.getOperation() == 0) {
            //是点赞，将评论回复的likes数量加1
            apComment.setLikes(apComment.getLikes() + 1);
            mongoTemplate.save(apComment);

            //不仅仅要增加点赞数，还需要记录当前用户对于当前评论的点赞数据记录
            //保存评论点赞数据(记录是谁点的赞)
            ApCommentLike apCommentLike = new ApCommentLike();
            apCommentLike.setCommentId(apComment.getId());
            apCommentLike.setAuthorId(user.getId());
            mongoTemplate.save(apCommentLike);
        } else {
            //是取消点赞，更新评论点赞数量
            int tmp = apComment.getLikes() - 1;
            //确保点赞数量不小于0。
            tmp = tmp < 1 ? 0 : tmp;
            apComment.setLikes(tmp);
            mongoTemplate.save(apComment);

            //删除该用户的评论点赞记录
            //构建一个查询来查找数据库中与当前评论回复ID和用户ID匹配的点赞记录
            Query query = Query.query(Criteria.where("commentId").is(apComment.getId()).and("authorId").is(user.getId()));
            mongoTemplate.remove(query, ApCommentLike.class);
        }

        //4.取消点赞
        Map<String, Object> result = new HashMap<>();
        log.info("更新后的点赞数量：{}",apComment.getLikes());
        result.put("likes", apComment.getLikes());
        return ResponseResult.okResult(result);
    }

    /**
     * 加载评论列表
     * @param dto
     * @return
     */
    @Override
    public ResponseResult findByArticleId(CommentDto dto) {
        log.info("加载评论列表");
        //1.检查参数
        if (dto == null || dto.getArticleId() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        //要加载的最大评论数量
        int size = 10;

        //2.加载数据(以文章ID为条件查询：这是哪个文章下的评论)
        //创建一个Query对象来查询entryId与dto中articleId匹配
        // 且createdTime早于dto中的minDate的评论。
        Query query = Query.query(Criteria.where("entryId")
                .is(dto.getArticleId()).and("createdTime").lt(dto.getMinDate()));
        //对查询结果按createdTime字段进行降序排序   //设置查询结果的限制为先加载最多10条记录
        query.with(Sort.by(Sort.Direction.DESC, "createdTime")).limit(size);
        List<ApComment> list = mongoTemplate.find(query, ApComment.class);

        //3.数据封装返回
        //3.1 用户未登录
        //获取当前用户的登录信息
        ApUser user = AppThreadLocalUtil.getUser();
        if (user == null) {
            log.info("用户未登录，返回的结果是：{}",list);
            return ResponseResult.okResult(list);
        }

        //3.2 用户已登录

        //需要查询当前评论中哪些数据被点赞了
        List<String> idList = list.stream().map(x -> x.getId()).collect(Collectors.toList());
        //TODO 创建第二个Query以查找哪些评论被当前登录用户（由authorId匹配）点赞了
        //如果当天登录人点赞了某条评论，需要高亮展示“点赞按钮”
        Query query1 = Query.query(Criteria.where("commentId")
                .in(idList).and("authorId").is(user.getId()));
        //APP评论信息的点赞信息
        List<ApCommentLike> apCommentLikes = mongoTemplate.find(query1, ApCommentLike.class);
        //获取apCommentLikes列表，
        if (apCommentLikes == null) {
            // 如果没有找到点赞记录，则返回原始的评论列表。
            return ResponseResult.okResult(list);
        }
        //创建一个空的resultList列表来存储最终要返回给用户的评论视图对象。
        List<CommentVo> resultList = new ArrayList<>();
        //遍历每个ApComment对象（x），
        // 创建一个新的CommentVo对象（视图对象）。
        list.forEach(x -> {
            CommentVo vo = new CommentVo();
            //复制属性从x到vo。
            BeanUtils.copyProperties(x, vo);
            for (ApCommentLike apCommentLike : apCommentLikes) {
                //检查当前评论是否在点赞列表中。
                // 若是，则设置vo的操作状态为0（表示用户已点赞）
                if (x.getId().equals(apCommentLike.getCommentId())) {
                    vo.setOperation((short) 0);
                    break;
                }
            }
            //将处理后的vo添加到结果列表中。
            resultList.add(vo);
        });
        //返回包含已处理的评论视图对象列表的成功响应。
        return ResponseResult.okResult(resultList);
    }
}
